﻿using System;
using YourWorld.Common.GreenWorldEntitiesService;
using System.Data.Services.Client;
using System.Linq;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using MainGameModule.ViewModels;
using BusinessObjects;
using System.Diagnostics;
using YourWorld.Common.Infrastucture.Events;

namespace MainGameModule.Models
{
    public class RubbishBinsRepository
    {
        private const string ServiceUrl = @"http://48de1d712dd7438f8e308ea3b1e69aae.cloudapp.net/GreenWorldDataService.svc";
        private GreenWorldEntities entities;

        private List<string> Colors = new List<string>() 
        {           
            "#FF1D57A9", //metal
            "#FFEF4316", //paper
            "#FFDCB44E", //plastic
            "#FF59A250", //glass
            "#FF942E38", //ATR
            "#FF67686E"
        };

        private List<string> PaleColors = new List<string>() 
        {           
            "#FF84A9DC",
            "#FF8B260C",
            "#FFAB7E0D",
            "#FF216A18",
            "#FFCC626C",
            "#FF67686E"
        };

        private List<string> Images = new List<string>() 
        {           
            "images/recyclingMetalBin.jpg",
            "images/recyclingPaperBin.jpg",
            "images/recyclingPlasticBin.jpg",
            "images/recyclingGlassBin.jpg",
            "images/recyclingATRBin.jpg",
            "images/recyclingATRBin.jpg"
        };

        private static RubbishBinsRepository instance;

        private RubbishBinsRepository()
        {
            this.entities = new GreenWorldEntities( new Uri( ServiceUrl, UriKind.RelativeOrAbsolute ) );
            this.PlayerBinsCollection = new ObservableCollection<BinViewModel>();
            this.MapBinsCollection = new ObservableCollection<BinViewModel>();
        }

        public Player Player
        {
            get;
            set;
        }

        public static RubbishBinsRepository Instance
        {
            get
            {
                if ( instance == null )
                    instance = new RubbishBinsRepository();

                return instance;
            }
        }

        public ObservableCollection<BinViewModel> PlayerBinsCollection
        {
            get;
            private set;
        }

        public ObservableCollection<BinViewModel> MapBinsCollection
        {
            get;
            private set;
        }

        public void Initialize()
        {
            this.LoadBinsCollection();
        }

        public void ClearValues()
        {
            foreach ( BinViewModel bin in this.PlayerBinsCollection )
                bin.ContentItems.Clear();
        }

        public void AddRubbsihToBin( Rubbish rubbish, int binId )
        {
            Debug.Assert( rubbish.MaterialTypeId == binId,
                String.Format( "The bin with Id {0} shouldn't be able to hold this rubbish - with Id {1}", rubbish.Id, binId ) );

            BinViewModel bin = this.PlayerBinsCollection.Where( x => x.MaterialId == binId ).FirstOrDefault();
            BinViewModel mapBin = this.MapBinsCollection.Where( x => x.MaterialId == binId ).FirstOrDefault();

            Debug.Assert( bin != null, "Bin not found!" );
            Debug.Assert( mapBin != null, "Bin not found!" );

            bin.ContentItems.Add( rubbish );
            bin.ContentWidth = bin.ContentItems.Count * Consts.CollectRubbishStep;

            bin.FillPercent += Consts.CollectedRubbishPercent;

            mapBin.ContentItems.Add( rubbish );
            mapBin.ContentWidth = mapBin.ContentItems.Count * Consts.CollectRubbishStep;
        }

        public void AddRubbsihToMapBin( Rubbish rubbish, int binId )
        {
            Debug.Assert( rubbish.MaterialTypeId == binId,
                String.Format( "The bin with Id {0} shouldn't be able to hold this rubbish - with Id {1}", rubbish.Id, binId ) );

            BinViewModel mapBin = this.MapBinsCollection.Where( x => x.MaterialId == binId ).FirstOrDefault();
            Debug.Assert( mapBin != null, "Bin not found!" );

            mapBin.ContentItems.Add( rubbish );
            mapBin.ContentWidth = mapBin.ContentItems.Count * Consts.CollectRubbishStep;
        }

        private void LoadBinsCollection()
        {
            var materialTypes = ( from r in entities.Materials select r ) as DataServiceQuery<Material>;
            materialTypes.BeginExecute( new AsyncCallback( this.LoadMaterialTypesCompleted ), materialTypes );
        }

        private void LoadMaterialTypesCompleted( IAsyncResult state )
        {
            var materialTypes = state.AsyncState as DataServiceQuery<Material>;

            List<Material> ros = materialTypes.EndExecute( state ).ToList();

            int i = 0;
            foreach ( Material material in ros )
            {
                if ( material.Type == Consts.UnSpecifiedBinType )
                    continue;

                BinViewModel bin = new BinViewModel()
                {
                    Name = material.Type,
                    MaterialId = material.Id,
                    Color = this.Colors[i],
                    Image = this.Images[i],
                    SecondColor = this.PaleColors[i],
                    Description = material.Description
                };

                BinViewModel bin2 = new BinViewModel()
                {
                    Name = material.Type,
                    MaterialId = material.Id,
                    Color = this.Colors[i],
                    Description = material.Description
                };

                this.PlayerBinsCollection.Add( bin );
                this.MapBinsCollection.Add( bin2 );
                i++;
            }
        }

        public bool CanIWinBadge()
        {
            if ( this.Player == null )
                return false;

            foreach ( Badge badge in BadgesRepository.Instance.Badges )
            {
                BadgeType type = BadgesRepository.Instance.BadgeTypes.Where( x => x.ID == badge.Type ).FirstOrDefault();
                Debug.Assert( type != null );

                if ( type.Key == null || type.TargetId == 0 )
                    continue;

                //If the player already has this badge:
                if ( this.Player.BadgesCollection.Where( x => x.Id == badge.ID ).Count() > 0 )
                    continue;

                UserBadge sameTypeBadge = this.Player.BadgesCollection.Where( x => x.TypeId == type.ID ).OrderBy( x => x.TargetItems ).FirstOrDefault();
                int alreadyWon = sameTypeBadge == null ? 0 : sameTypeBadge.TargetItems;

                foreach ( BinViewModel bin in RubbishBinsRepository.Instance.PlayerBinsCollection )
                {
                    if ( type.TargetId == null || bin.MaterialId != ( int )type.TargetId )
                        continue;

                    if ( bin.ContentItems.Count + alreadyWon == badge.MinimumItems )
                    {
                        this.Player.BadgesCollection.Add( BadgesRepository.Instance.GetBadge( badge.ID ) );
                        this.Player.Badges = String.Format( "{0},{1}", badge.ID, this.Player.Badges );
                        EventService.Aggregator.GetEvent<ShowBadgesEvent>().Publish( badge.ID );

                        return true;
                    }
                }
            }

            return false;
        }
    }
}
